package com.laopan.elasticsearch.core.operation;

import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.laopan.elasticsearch.bean.UpdateFieldArray;
import com.laopan.elasticsearch.bean.UpdateFieldInfo;
import org.elasticsearch.action.DocWriteResponse;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.List;

/**
 * 文档的实际操作者
 *
 * @author laopan
 * @className EsDocOperation
 * @date 2021/4/16 15:57
 */

public class DocOperation {
    private static final Logger log = LoggerFactory.getLogger(DocOperation.class);

    private RestHighLevelClient highLevelClient;

    public DocOperation(RestHighLevelClient highLevelClient) {
        this.highLevelClient = highLevelClient;
    }

    /**
     * 文档数据是否存在
     *
     * @param index
     * @param id
     * @return
     */
    public boolean exists(String index, String id) {
        GetRequest request = new GetRequest(index, id);
        boolean exists = false;
        try {
            return highLevelClient.exists(request, RequestOptions.DEFAULT);
        } catch (IOException e) {
            log.error("get elasticsearch index:[{}],id:[{}] isExists exception;{} ", index, id, e);
        }
        return false;
    }

    public boolean saveDoc(String index, String json, String id) {
        IndexRequest indexRequest = new IndexRequest(index);
        if (null != id && id.trim().length() > 0) {
            indexRequest.id(id);
        }
        indexRequest.source(json, XContentType.JSON);
        try {
            IndexResponse indexResponse =
                    highLevelClient.index(indexRequest, RequestOptions.DEFAULT);
            if (null != indexResponse) {
                if (indexResponse.getResult() == DocWriteResponse.Result.CREATED) {
                    log.info("add index:[{}]doc：[{}] success", index, id);
                } else if (indexResponse.getResult() == DocWriteResponse.Result.UPDATED) {
                    log.info("update index:[{}] doc：[{}] success", index, id);
                }
                return true;
            } else {
                log.info("save index:[{}] doc：[{}] fail", index, id);
            }
        } catch (IOException e) {
            log.error("save index:[{}] doc：[{}] exception", index, id, e);
        }
        return false;
    }

    public BulkResponse saveBatchDoc(String index, JsonArray dataList, String idField) {
        try {
            BulkRequest bulkRequest = new BulkRequest();
            for (JsonElement object : dataList) {
                JsonObject jsonObject = object.getAsJsonObject();
                String idData = jsonObject.get(idField).getAsString();
                IndexRequest indexRequest = new IndexRequest(index);
                if (null != idData && idData.trim().length() > 0) {
                    indexRequest.id(idData);
                }
                indexRequest.source(jsonObject.toString(), XContentType.JSON);
                bulkRequest.add(indexRequest);
            }
            BulkResponse resp = highLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
            log.error("save batch doc data,index :[{}],result:{} ", index, resp.hasFailures());
            return resp;
        } catch (Exception e) {
            log.error("save batch doc data,index :[{}] exception:{} ", index, e);
        }
        return null;
    }

    public boolean deleteDocById(String index, String id) {
        if (exists(index, id)) {
            log.info("starting deleteSingleDoc index:[{}],id:[{}] ", index, id);
            DeleteRequest deleteRequest = new DeleteRequest(index, id);
            try {
                DeleteResponse response = highLevelClient.delete(deleteRequest, RequestOptions.DEFAULT);
                if (null != response && DocWriteResponse.Result.DELETED == response.getResult()) {
                    return true;
                }
            } catch (Exception e) {
                log.error("deleteSingleDoc index:[{}],id:[{}] , exception;{} ", index, id, e);
            }
        } else {
            log.info("deleteSingleDoc index:[{}],id:[{}] fail,data is not exits ", index, id);
        }
        return false;
    }

    public UpdateResponse updateField(String index, UpdateFieldInfo fieldInfo) {
        String id = fieldInfo.getId();
        if (exists(index, id)) {
            XContentBuilder updateContent = fieldInfo.getUpdateContent();
            if (null != updateContent) {
                return updateField(index, fieldInfo.getId(), updateContent);
            }
        }
        return null;
    }

    public UpdateResponse updateField(String index, String id, XContentBuilder updateContent) {
        UpdateRequest updateRequest = new UpdateRequest(index, id).doc(updateContent);
        return updateResponse(updateRequest);
    }

    private UpdateResponse updateResponse(UpdateRequest updateRequest) {
        if (null != updateRequest) {
            try {
                UpdateResponse updateResponse = highLevelClient.update(updateRequest, RequestOptions.DEFAULT);
                if (null != updateResponse) {
                    log.info("update index：[{}]  id：[{}] result:[{}]", updateResponse.getIndex(), updateResponse.getId(), updateResponse.getResult());
                }
                return updateResponse;
            } catch (IOException e) {
                log.error("update index [{}] exception：{}", updateRequest.index(), e);
            }
        }
        return null;
    }

    public UpdateResponse updateArrayField(String index, UpdateFieldArray fieldArray) {
        String id = fieldArray.getId();
        if (exists(index, id)) {
            XContentBuilder updateContent = fieldArray.getUpdateContent();
            if (null != updateContent) {
                return updateField(index, fieldArray.getId(), updateContent);
            }
        }
        return null;
    }

    public BulkResponse updateBatchFieldArray(String index, List<UpdateFieldArray> fieldArrays) {
        try {
            BulkRequest bulkRequest = new BulkRequest();
            fieldArrays.forEach(fieldArray -> {
                XContentBuilder updateContent = fieldArray.getUpdateContent();
                if (null != updateContent) {
                    bulkRequest.add(new UpdateRequest(index, fieldArray.getId()).doc(updateContent));
                }
            });
            BulkResponse resp = highLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
            log.info("update elasticsearch data,index :[{}] result;{} ", index, resp.hasFailures());
            return resp;
        } catch (Exception e) {
            log.error("update elasticsearch data,index :[{}] exception;{} ", index, e);
        }
        return null;
    }

    public BulkResponse updateBatchField(String index, List<UpdateFieldInfo> fieldInfos) {
        BulkRequest bulkRequest = new BulkRequest();
        try {
            fieldInfos.forEach(fieldInfo -> {
                XContentBuilder updateContent = fieldInfo.getUpdateContent();
                if (null != updateContent) {
                    bulkRequest.add(new UpdateRequest(index, fieldInfo.getId()).doc(updateContent));
                }
            });
            BulkResponse resp = highLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
            log.info("update index :[{}] data result;{} ", index, resp.hasFailures());
            return resp;
        } catch (Exception e) {
            log.error("update index :[{}] data exception;{} ", index, e);
        }
        return null;
    }
}
